package demoMod.nanaki.powers;

import com.megacrit.cardcrawl.actions.AbstractGameAction;
import com.megacrit.cardcrawl.actions.animations.VFXAction;
import com.megacrit.cardcrawl.actions.common.DamageAction;
import com.megacrit.cardcrawl.actions.common.DamageAllEnemiesAction;
import com.megacrit.cardcrawl.actions.common.ReducePowerAction;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.cards.DamageInfo;
import com.megacrit.cardcrawl.characters.AbstractPlayer;
import com.megacrit.cardcrawl.core.AbstractCreature;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.localization.PowerStrings;
import com.megacrit.cardcrawl.powers.AbstractPower;
import com.megacrit.cardcrawl.powers.MinionPower;
import com.megacrit.cardcrawl.relics.AbstractRelic;
import com.megacrit.cardcrawl.vfx.GainPennyEffect;
import demoMod.nanaki.NanakiMod;
import demoMod.nanaki.interfaces.NoteApplyHook;
import demoMod.nanaki.interfaces.NoteExplodeHook;
import demoMod.nanaki.relics.MidasTouch;
import demoMod.nanaki.utils.GetWaitAction;
import demoMod.nanaki.vfx.NoteFlashEffect;

import java.util.stream.Collectors;

public class NotePower extends AbstractPower {
    public static final String POWER_ID = NanakiMod.makeID("NotePower");
    private static final PowerStrings powerStrings;
    public static final String NAME;
    public static final String[] DESC;
    private boolean killedByNote = false;

    public NotePower(AbstractCreature owner, int amount) {
        this.name = NAME;
        this.ID = POWER_ID;
        this.owner = owner;
        this.amount = amount;
        this.type = PowerType.DEBUFF;
        this.updateDescription();
        this.loadRegion("hymn");
    }

    @Override
    public void onInitialApplication() {
        for (AbstractCard card : AbstractDungeon.player.drawPile.group.stream().filter(c -> c instanceof NoteApplyHook).collect(Collectors.toList())) {
            this.amount = ((NoteApplyHook) card).onApplyNote(this.owner, this.amount);
        }
        for (AbstractRelic relic : AbstractDungeon.player.relics.stream().filter(r -> r instanceof NoteApplyHook).collect(Collectors.toList())) {
            this.amount = ((NoteApplyHook) relic).onApplyNote(this.owner, this.amount);
        }
        checkExplode();
    }

    private void checkExplode() {
        int explodeAmount = 25;
        if (AbstractDungeon.player.hasRelic(NanakiMod.makeID("SpellBottle"))) {
            explodeAmount += 9;
        }
        boolean shouldExplode = true;
        for (AbstractPower power : owner.powers.stream().filter(abstractPower -> abstractPower instanceof NoteExplodeHook).collect(Collectors.toList())) {
            shouldExplode = shouldExplode && ((NoteExplodeHook) power).shouldExplode(owner);
        }
        for (AbstractPower power : AbstractDungeon.player.powers.stream().filter(abstractPower -> abstractPower instanceof NoteExplodeHook).collect(Collectors.toList())) {
            shouldExplode = shouldExplode && ((NoteExplodeHook) power).shouldExplode(owner);
        }
        if (amount >= explodeAmount && shouldExplode) {
            this.flash();
            int reduceAmount = amount;
            int damageAmount = amount;
            if (!(owner instanceof AbstractPlayer)) {
                for (AbstractPower power : owner.powers.stream().filter(abstractPower -> abstractPower instanceof NoteExplodeHook).collect(Collectors.toList())) {
                    reduceAmount = ((NoteExplodeHook) power).reduceExplodeAmount(reduceAmount);
                    damageAmount = ((NoteExplodeHook) power).modifyExplodeDamage(damageAmount);
                }
            }
            for (AbstractPower power : AbstractDungeon.player.powers.stream().filter(abstractPower -> abstractPower instanceof NoteExplodeHook).collect(Collectors.toList())) {
                reduceAmount = ((NoteExplodeHook) power).reduceExplodeAmount(reduceAmount);
                damageAmount = ((NoteExplodeHook) power).modifyExplodeDamage(damageAmount);
            }
            for (AbstractRelic relic : AbstractDungeon.player.relics.stream().filter(r -> r instanceof NoteExplodeHook).collect(Collectors.toList())) {
                reduceAmount = ((NoteExplodeHook) relic).reduceExplodeAmount(reduceAmount);
                damageAmount = ((NoteExplodeHook) relic).modifyExplodeDamage(damageAmount);
            }
            addToTop(new ReducePowerAction(owner, owner, POWER_ID, reduceAmount));
            addToTop(GetWaitAction.doAndWait(() -> {
                if (owner.isDeadOrEscaped() && !owner.halfDead) {
                    killedByNote = true;
                }
            }, 0.0F));
            if (AbstractDungeon.player.hasRelic("IsaacExt:Birthright")) {
                addToTop(new DamageAllEnemiesAction(AbstractDungeon.player, DamageInfo.createDamageMatrix(damageAmount, true), DamageInfo.DamageType.THORNS, AbstractGameAction.AttackEffect.FIRE));
            } else {
                addToTop(new DamageAction(owner, new DamageInfo(owner, damageAmount, DamageInfo.DamageType.THORNS), AbstractGameAction.AttackEffect.FIRE));
            }
            addToTop(new VFXAction(new NoteFlashEffect(owner.hb.cX, owner.hb.cY)));
        }
    }

    @Override
    public void onDeath() {
        AbstractPlayer p = AbstractDungeon.player;
        if (p.hasRelic(MidasTouch.ID) && !owner.hasPower(MinionPower.POWER_ID) && killedByNote) {
            p.getRelic(MidasTouch.ID).flash();
            p.gainGold(20);
            for(int i = 0; i < 20; ++i) {
                AbstractDungeon.effectList.add(new GainPennyEffect(p, owner.hb.cX, owner.hb.cY, p.hb.cX, p.hb.cY, true));
            }
        }
    }

    @Override
    public void stackPower(int stackAmount) {
        for (AbstractCard card : AbstractDungeon.player.drawPile.group.stream().filter(c -> c instanceof NoteApplyHook).collect(Collectors.toList())) {
            stackAmount = ((NoteApplyHook) card).onApplyNote(this.owner, stackAmount);
        }
        for (AbstractRelic relic : AbstractDungeon.player.relics.stream().filter(r -> r instanceof NoteApplyHook).collect(Collectors.toList())) {
            stackAmount = ((NoteApplyHook) relic).onApplyNote(this.owner, stackAmount);
        }
        super.stackPower(stackAmount);
        checkExplode();
    }

    @Override
    public void updateDescription() {
        int explodeAmount = 25;
        if (AbstractDungeon.player.hasRelic(NanakiMod.makeID("SpellBottle"))) {
            explodeAmount += 9;
        }
        int damageAmount = amount;
        for (AbstractPower power : owner.powers.stream().filter(abstractPower -> abstractPower instanceof NoteExplodeHook).collect(Collectors.toList())) {
            damageAmount = ((NoteExplodeHook) power).modifyExplodeDamage(damageAmount);
        }
        this.description = String.format(DESC[0], this.amount, this.amount, explodeAmount, damageAmount / (float) amount);
    }

    @Override
    public float atDamageReceive(float damage, DamageInfo.DamageType type) {
        if (type == DamageInfo.DamageType.NORMAL) {
            return damage * (100 + this.amount) / 100.0F;
        }
        return damage;
    }

    @Override
    public float atDamageGive(float damage, DamageInfo.DamageType type) {
        if (type == DamageInfo.DamageType.NORMAL) {
            return damage * (100 - this.amount) / 100.0F;
        }
        return damage;
    }

    static {
        powerStrings = CardCrawlGame.languagePack.getPowerStrings(POWER_ID);
        NAME = powerStrings.NAME;
        DESC = powerStrings.DESCRIPTIONS;
    }
}
